package com.example.chatrecommendation.controller;

import com.example.chatrecommendation.bean.ChattingRecords;
import com.example.chatrecommendation.bean.dto.ChattingAddDto;
import com.example.chatrecommendation.bean.dto.ChattingSendDto;
import com.example.chatrecommendation.bean.dto.ChattingUpdateNameDto;
import com.example.chatrecommendation.bean.dto.Messages;
import com.example.chatrecommendation.bean.vo.ChattingListVo;
import com.example.chatrecommendation.bean.vo.ChattingSendVo;
import com.example.chatrecommendation.bean.vo.PPTLink;
import com.example.chatrecommendation.bean.vo.VideoLink;
import com.example.chatrecommendation.service.ChattingRecordsService;
import com.example.chatrecommendation.service.impl.AiPaintingServiceImpl;
import com.example.chatrecommendation.tool.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Jasmine-drs
 * @date 2024/5/21 20:31
 */

@Slf4j
@Api("聊天模块")
@RestController
@RequestMapping("/chat")
public class ChatController {

    private final ChattingRecordsService chattingRecordsService;
    private final com.example.chatrecommendation.tool.Api API;
    private final AiPaintingServiceImpl aiPaintingService;

    public ChatController(ChattingRecordsService chattingRecordsService, com.example.chatrecommendation.tool.Api api, AiPaintingServiceImpl aiPaintingService) {
        this.chattingRecordsService = chattingRecordsService;
        API = api;
        this.aiPaintingService = aiPaintingService;
    }

    /**
     * 获取聊天记录列表
     * 通过学生账号
     *
     * @param studentAccount 学生账号
     * @param type           聊天类型，0为普通聊天，其他为智能体id聊天
     * @return 历史记录列表，已经按时间倒序排列
     */
    @GetMapping("/getChatRecordsList")
    @ApiOperation("获取聊天记录列表")
    public R<List<ChattingListVo>> getChatRecordsList(@RequestParam Integer studentAccount, @RequestParam Integer type) {
        List<ChattingListVo> chattingListVos = chattingRecordsService.getChatRecords(studentAccount, type);
        return R.success(chattingListVos);
    }

    /**
     * 根据对应聊天记录的id获取历史聊天内容
     *
     * @param id 聊天记录的id
     * @return 历史记录
     */
    @GetMapping("/getChatRecords")
    @ApiOperation("获取聊天记录")
    public R<List<Messages>> getChatRecords(@RequestParam Integer id) {
        ChattingRecords byId = chattingRecordsService.getById(id);
//		返回数组聊天记录
        String message = byId.getMessage();
        List<Messages> cen = new ArrayList<>();
//		解析message
        JSONArray messagesArray = new JSONArray(message);
        for (int i = 0; i < messagesArray.length(); i++) {
            JSONObject messageObject = messagesArray.getJSONObject(i);
            String role = messageObject.getString("role");
            String content = messageObject.getString("content");
            cen.add(new Messages(role, content));
        }
        return R.success(cen);
    }

    private static List<Map<String, Object>> createExampleData() {
        List<Map<String, Object>> data = new ArrayList<>();

        // 示例数据结构
        data.add(createNode(1, 667136, "被解释", 11, new HashMap<>(), "java.exe", "Java解释器", ".class", "Java字节码"));
        data.add(createNode(2, 801146, "编译产生", 1351, new HashMap<>(), ".class", "Java字节码文件", ".java", "Java源代码"));

        return data;
    }

    private static Map<String, Object> createNode(
            int startNodeId, int id, String type, int endNodeId,
            Map<String, String> properties, String relatedProperty,
            String relatedLabel, String nodeProperty, String nodeLabel) {

        Map<String, Object> node = new HashMap<>();
        Map<String, Object> relationship = new HashMap<>();
        relationship.put("startNodeId", startNodeId);
        relationship.put("id", id);
        relationship.put("type", type);
        relationship.put("endNodeId", endNodeId);
        relationship.put("properties", properties);

        Map<String, Object> related = new HashMap<>();
        related.put("id", endNodeId);
        related.put("properties", Map.of("名称", relatedProperty));
        related.put("labels", List.of(relatedLabel));

        Map<String, Object> nodeData = new HashMap<>();
        nodeData.put("id", startNodeId);
        nodeData.put("properties", Map.of("extension", nodeProperty));
        nodeData.put("labels", List.of(nodeLabel));

        node.put("r", relationship);
        node.put("related", related);
        node.put("n", nodeData);

        return node;
    }

    /**
     * 进行聊天对话
     *
     * @param chattingSendDto 用户消息
     * @return 回答内容，流式输出
     */
    @PostMapping("/send")
    @ApiOperation("发送聊天")
/*    public R send(@RequestBody ChattingSendDto chattingSendDto) throws Exception {
        // 删除role值为assistant并且content值为空的假数据
        if (chattingSendDto != null && chattingSendDto.getMessage() != null) {
            chattingSendDto.getMessage().removeIf(message -> "assistant".equals(message.getRole()) && message.getContent() != null && message.getContent().isEmpty());
        }
        ChattingSendVo chattingSendVo = new ChattingSendVo();
        String aiImg = "";
        // 判断用户提示词是否意为使用ai绘画，且要求这些词必须位于句子开头
        String patternString = "^(画一|画图|请你画|请画)";
        Pattern pattern = Pattern.compile(patternString);
        String content = chattingSendDto.getMessage().get(chattingSendDto.getMessage().size() - 1).getContent();
        Matcher matcher = pattern.matcher(content);
        if (matcher.find()) {
            //优先使用StableDiffusion,如果出现异常,调用讯飞星火绘画接口sparkAiPainting
            try {
                aiImg = aiPaintingService.generateImage(matcher.replaceFirst(""));
            } catch (Exception e) {
                log.error("StableDiffusion绘画接口调用失败，使用默认接口");
                aiImg = aiPaintingService.sparkAiPainting(content);
            }
            chattingSendVo.setAiPainting(aiImg);
        } else {
            // 创建CompletableFuture实例，用于异步执行任务
            // 异步获取知识图谱数据
            CompletableFuture<List<Map<String, Object>>> knowledgeGraphFuture = CompletableFuture.supplyAsync(() ->
                    API.getKnowledgeGraph(chattingSendDto.getMessage()));

            // 当知识图谱数据获取完成后，使用其结果来异步调用大模型回答问题
            CompletableFuture<String> largeModelFuture = knowledgeGraphFuture.thenApplyAsync(knowledgeGraph -> {
                //4. 修改列表第一个系统级别提示词为知识图谱输入
                chattingSendDto.getMessage().get(0).setContent("你是一个在“思议”在线教育平台工作的乐于助人的学习助手，名字叫做“思议灵犀”，请根据外带知识图谱输入回答问题，如果知识图谱输入为空，则自行思考回答，每次回答长度简短一百字左右，不要太简单也不要太复杂\\n知识图谱输入：" + knowledgeGraph);
                // 调用大模型回答问题
                return API.callLargeModel(chattingSendDto.getMessage());
            });
            // 异步获取PPT和视频数据
            CompletableFuture<Pair<List<PPTLink>, List<VideoLink>>> pptAndVideoFuture = CompletableFuture.supplyAsync(() ->
                    API.getPPTAndVideo(chattingSendDto.getMessage()));


            // 等待所有异步任务完成
            CompletableFuture<Void> allFutures = CompletableFuture.allOf(knowledgeGraphFuture, pptAndVideoFuture, largeModelFuture);
            try {
                allFutures.get(); // 等待所有任务完成
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
                return R.err("异步执行出错");
            }

            // 获取异步执行结果
            try {
                chattingSendVo.setKnowledgeGraph(knowledgeGraphFuture.get());
                chattingSendVo.setPptLink(pptAndVideoFuture.get().getKey());
                chattingSendVo.setVideoLink(pptAndVideoFuture.get().getValue());
                String replace = largeModelFuture.get().replace("\\n", "<br>");
                chattingSendVo.setContent(replace);
//                System.out.println(aiImg);
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
                return R.err("获取异步结果出错");
            }
            List<Messages> list = new ArrayList<>();
            //		找到最新的用户提问
            Messages messages = chattingSendDto.getMessage().get(chattingSendDto.getMessage().size() - 1);
//		构建最新的对话
            list.add(new Messages(messages.getRole(), messages.getContent()));
            list.add(new Messages("assistant", chattingSendVo.getContent()));
            chattingRecordsService.saveChatRecords(chattingSendDto.getId(), list);
        }
        return R.success(chattingSendVo);
    }*/
    public R send(@RequestBody ChattingSendDto chattingSendDto) {
        // 删除role值为assistant并且content值为空的假数据
        if (chattingSendDto != null && chattingSendDto.getMessage() != null) {
            chattingSendDto.getMessage().removeIf(message -> "assistant".equals(message.getRole()) && message.getContent() != null && message.getContent().isEmpty());
        }
        ChattingSendVo chattingSendVo = new ChattingSendVo();
        // 创建一个64x64像素的BufferedImage
        BufferedImage image = new BufferedImage(64, 64, BufferedImage.TYPE_INT_RGB);

        // 用红色填充图像
        for (int y = 0; y < 64; y++) {
            for (int x = 0; x < 64; x++) {
                image.setRGB(x, y, 0xC71D23); // 红色
            }
        }

        // 将BufferedImage转换为字节数组
        byte[] imageBytes = null;
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            ImageIO.write(image, "png", baos);
            imageBytes = baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        String aiImg = Base64.getEncoder().encodeToString(imageBytes);
        ;
        // 判断用户提示词是否意为使用ai绘画，且要求这些词必须位于句子开头
        String patternString = "^(画一|画图|请你画|请画)";
        Pattern pattern = Pattern.compile(patternString);
        String content = chattingSendDto.getMessage().get(chattingSendDto.getMessage().size() - 1).getContent();
        Matcher matcher = pattern.matcher(content);
        if (matcher.find()) {
            chattingSendVo.setAiPainting(aiImg);
        } else {
            String response = new String();
            response = "这是一段测试文本，为节约回答Token。这是一段测试文本，为节约回答Token。这是一段测试文本，为节约回答Token。这是一段测试文本，为节约回答Token。这是一段测试文本，为节约回答Token。";
            chattingSendVo.setContent(response);

            List<PPTLink> pptLinks = new ArrayList<>();
            PPTLink pptLink = new PPTLink();
            pptLink.setName("Java历史.ppt");
            pptLink.setSrc("/ppt/1/Java历史.png");
            pptLink.setPptSrc("/ppt/1/Java历史.ppt");
            pptLinks.add(pptLink);
            PPTLink pptLink2 = new PPTLink();
            pptLink2.setName("Java历史.ppt");
            pptLink2.setSrc("/ppt/1/Java历史.png");
            pptLink2.setPptSrc("/ppt/1/Java历史.ppt");
            pptLinks.add(pptLink2);
            PPTLink pptLink3 = new PPTLink();
            pptLink3.setName("Java历史.ppt");
            pptLink3.setSrc("/ppt/1/Java历史.png");
            pptLink3.setPptSrc("/ppt/1/Java历史.ppt");
            pptLinks.add(pptLink3);
            chattingSendVo.setPptLink(pptLinks);

            List<VideoLink> videoLinks = new ArrayList<>();
            VideoLink videoLink = new VideoLink();
            videoLink.setName("9.2throw语句.mp4");
            videoLink.setSrc("/video/9/9.2throw语句.png");
            videoLink.setVideoSrc("/video/9/9.2throw语句.mp4");
            videoLinks.add(videoLink);
            videoLinks.add(videoLink);
            VideoLink videoLink2 = new VideoLink();
            videoLink2.setName("9.3自定义异常.mp4");
            videoLink2.setSrc("/video/9/9.3自定义异常.png");
            videoLink2.setVideoSrc("/video/9/9.3自定义异常.mp4");
            videoLinks.add(videoLink2);
            chattingSendVo.setVideoLink(videoLinks);

            // 假设这是从图数据库查询到的节点信息
            List<Map<String, Object>> fakeNodes = createExampleData();

            // 创建假节点
            chattingSendVo.setKnowledgeGraph(fakeNodes);
        }
        return R.success(chattingSendVo);
    }

    /**
     * 删除聊天记录
     *
     * @param id 聊天记录id
     * @return 是否成功
     */
    @DeleteMapping("/deleteChat")
    @ApiOperation("删除聊天记录")
    public R<String> deleteChat(@RequestParam Integer id) {
        chattingRecordsService.removeById(id);
        return R.success("删除成功");
    }

    /**
     * 增加聊天记录，与智能体的聊天记录新增共用
     *
     * @param chattingAddDto 基础信息
     * @return 新的聊天记录信息
     */
    @PostMapping("/addChat")
    @ApiOperation("增加聊天记录")
    public R<ChattingRecords> addChat(@RequestBody ChattingAddDto chattingAddDto) {
        ChattingRecords chattingRecords = chattingRecordsService.addChatRecords(chattingAddDto);
        return R.success(chattingRecords);
    }

    /**
     * 修改聊天记录名字
     *
     * @param chattingUpdateNameDto 聊天记录修改数据
     * @return 是否成功
     */
    @PutMapping("/updateChatName")
    @ApiOperation("修改聊天记录名字")
    public R<String> updateChatName(@RequestBody ChattingUpdateNameDto chattingUpdateNameDto) {
        ChattingRecords chattingRecords = chattingRecordsService.getById(chattingUpdateNameDto.getId());
        chattingRecords.setName(chattingUpdateNameDto.getName());
        chattingRecordsService.updateById(chattingRecords);
        return R.success("修改成功");
    }

    /**
     * 优化提问语句
     *
     * @param question 用户提问
     * @return 优化后的语句
     */
    @GetMapping("/optimizeQuestion")
    @ApiOperation("优化提问语句")
    public R<String> optimizeQuestion(String question) {
        String optimizeQuestion = API.optimizeQuestion(question);
        optimizeQuestion = optimizeQuestion.replace("\\\"", "");
        return R.success(optimizeQuestion);
    }
}
